/*
	业务拓扑图
	//TODO: 考虑改变查看集群方式

*/
define(
	[
		'require',
		'zrender',
		'zrender/tool/util',
		'zrender/tool/event',
		'zrender/tool/area',
		'zrender/shape/Line',
		'zrender/shape/Image',
		'zrender/Group',
		'./arrow',
		'./nodepanel',
		'./relationline'
	],
	function(require) {
		"use strict";

		var zrender = require('zrender');
		var LineShape = require('zrender/shape/Line');
		var ImageShape = require('zrender/shape/Image');
		var Group = require('zrender/Group');

		var zrUtil = require('zrender/tool/util');
		var eventTool = require('zrender/tool/event');

		var Arrow = require('./arrow');
		var NodePanel = require('./nodepanel');
		var RelationLine = require('./relationline');

		var forEach = Ember.EnumerableUtils.forEach,
			map = Ember.EnumerableUtils.map;

		//业务拓扑图
		var BusinessTopo = Ember.Object.extend(Ember.Evented, {
			container: null,

			scaling: 1,

			init: function() {
				this.nodePanels = Ember.A();
				this.nodePanelsMap = {};
				this.clusterNodePanels = Ember.A();
				this.clusterNodePanelsMap = {};
				this.relationLines = Ember.A();
				this.initElement();
			},

			initElement: function() {
				if (!this.container) {
					return;
				}
				var dom = this.container;

				if (G_vmlCanvasManager && G_vmlCanvasManager.init) {
					G_vmlCanvasManager.initElement(dom);
				}

				this.width = $(dom).width();
				this.height = $(dom).height();

				var zr = this.zr = zrender.init(dom);

				zr.clear();

				if (!this.group) {
					var g = this.group = new Group();
					g.position[0] = 0;
					g.position[1] = 0;

					var mainG = this.mainGroup = new Group();
					mainG.position[0] = 0;
					mainG.position[1] = 0;

					zr.addElement(this.group);
					g.addChild(mainG);
				}

				this._addEventListner();
			},

			_addEventListner: function() {
				var me = this,
					g = this.group,
					runBind = Ember.run.bind;

				g.bind("dragend", runBind(this, "_groupDragend"));
				g.bind("drop", runBind(this, "_groupDrop"));
				g.bind("mousedown", runBind(this, "_groupMousedown"));
				g.bind("click", runBind(this, "_groupClick"));
				this.zr.on("mousedown", runBind(this, "_zrMousedown"));
				this.zr.on("mouseup", runBind(this, "_zrMouseup"));
				this.zr.on("mousemove", runBind(this, "_zrMousemove"));
				this.zr.on("mousewheel", runBind(this, "_zrMousewheele"));
			},

			render: function() {
				var zr = this.zr,
					data = this.data;
				//渲染出节点面板
				this._renderNodes(data && data.topoNodes || []);

				//渲染节点面板间连线
				this._renderLines(data && data.relations || []);
			},

			_renderNodes: function(nodes) {
				var me = this;
				var nodePanels = this.nodePanels;

				var nodePanelsMap = this.nodePanelsMap;

				forEach(nodes, function(node) {
					if (node.nodeType == 3) {
						return;
					}
					var panel = me._renderNode(node, "mainGroup");
					panel.render();
					nodePanels.push(panel);
					nodePanelsMap[node.id] = panel;
				});
			},

			_renderNode: function(node, groupName) {
				var me = this;
				var panel = NodePanel.create({
					id: node.id,
					x: node.x,
					y: node.y,
					draggable: node.nodeType != 3,
					displayMode: node.size,
					data: node,
					container: me,
					auth: me.get("auth"),
					groupName: groupName,
					timePoint: me.timePoint,
					menusConfig: me.menusConfig,
					onMenuClick: function(menuCode) {
						me.onMenuClick && me.onMenuClick(menuCode, this);
						me.trigger("menuClick", menuCode, this);
					},
					ondragstart: function() {
						me.draggingNode = this;
					},
					ondragend: function(e) {
						me.draggingNode = null;
						if (!me.droppingNode && this.draggable) {
							var movePos = e.target.position;
							e.target.position = [0, 0];
							var x = this.x + movePos[0];
							var y = this.y + movePos[1];
							this.position(x, y);
						}
					},
					onmouseenter: function(e) {
						if (me.isDraggingCanvas) {
							return;
						}
						if (me.isLinkMode) {
							this.hover();
							if (!me.isLinking) {
								me.lineBeginNodeNominee = this;
							} else {
								if (me.lineBeginNode) {
									me.lineEndNodeNominee = this;
								} else {
									Ember.Logger.log("line exception 1");
								}
							}
							return;
						}
						//$(me.container.children[0]).css("cursor", "");
						if (me.draggingNode) {
							this.hideMenus();
							if (me.draggingNode.data.nodeType != 2 &&
								this.data.nodeType != 3) {
								this.hover();
								this.largenBorder();
								me.droppingNode = this;
							}
							return;
						}
						switch (e.xtype) {
							case "stackMouseover":
								this.hoverStack();
								break;
							default:
								this.hover();
								this.showMenus(e);
								break;
						}
					},
					onmouseout: function(e) {
						if (me.isDraggingCanvas) {
							return;
						}
						if (me.isLinkMode) {
							this.unhover();
							if (!me.isLinking) {
								me.lineBeginNodeNominee = null;
							} else {
								if (me.lineBeginNode) {
									me.lineEndNodeNominee = null;
								} else {
									Ember.Logger.log("line exception 2");
								}
							}
							return;
						}
						//$(me.container.children[0]).css("cursor", "");
						if (me.draggingNode && me.draggingNode.data.nodeType != 2) {
							this.resumeBorder();
							this.unhover();
							me.droppingNode = null;
							return;
						}
						switch (e.xtype) {
							case "stackMouseout":
								this.unhoverStack();
								break;
							default:
								this.unhover();
								this.hideMenus();
								break;
						}
					}
				});
				return panel;
			},

			_renderLines: function(relations) {
				var me = this;
				var lines = this.relationLines;
				var nodePanelsMap = this.nodePanelsMap;

				forEach(relations, function(relation) {
					var fromPanel = nodePanelsMap[relation.from];
					var toPanel = nodePanelsMap[relation.to];
					if (!fromPanel || !toPanel) {
						return;
					}
					var line = RelationLine.create({
						container: me,
						menusConfig: me.menusConfig,
						groupName: "mainGroup",
						data: relation,
						auth: me.get("auth"),
						fromPanel: fromPanel,
						toPanel: toPanel,
						onMenuClick: function(menuCode) {
							me.onMenuClick && me.onMenuClick(menuCode, this);
							me.trigger("menuClick", menuCode, this);
						},
						onmouseover: function(e) {
							if (!me.isLinkMode && !me.draggingNode) {
								if (!me.get("auth.isNormal")) {
									this.showMenus(e);
								}
							}
						},
						onmouseout: function() {
							if (!me.get("auth.isNormal")) {
								this.hideMenus();
							}
						}
					});

					line.render();
					lines.push(line);
				});

			},

			_groupDragend: function(e) {
				this.refreshLines();
			},

			_groupDrop: function(e) {
				if (this.draggingNode && this.droppingNode) {
					this.dropNodeToNode && this.dropNodeToNode(this.draggingNode.data, this.droppingNode.data);
					this.trigger("dropNodeToNode", this.draggingNode.data, this.droppingNode.data);

					this.droppingNode.resumeBorder();
					this.droppingNode = null;
				}
			},

			_groupMousedown: function(e) {
				if (this.isLinkMode) {
					if (this.lineBeginNodeNominee) {
						this.container.style.cursor = "crosshair";
						this.lineBeginNode = this.lineBeginNodeNominee;
						this.isLinking = true;
						this._lineBeginPos = [eventTool.getX(e.event), eventTool.getY(e.event)];
					}
				}
			},

			_groupClick: function(e) {
				switch (e.xtype) {
					case "stackClick":
						this.onNodeStackClick && this.onNodeStackClick(e.targetNodePanel.data);
						this.trigger("nodeStackClick", e.targetNodePanel.data);
						break;
					case "pfmsItemClick":
						this.onNodePfmsClick && this.onNodePfmsClick(e.targetNodePanel.data, e.dataKey);
						this.trigger("nodePfmsClick", e.targetNodePanel.data, e.dataKey);
						break;
					default:
						break;
				}
			},

			_zrMousedown: function(e) {
				if (e.target || this.isLinkMode) {
					return;
				}

				this._dragAll(e);
			},

			_zrMousemove: function(e) {
				if (this.isDraggingCanvas) {
					this._moveAll(e);
					return;
				}
				if (!e.target && !this.isLinkMode && !this.isDraggingCanvas) {
					this.container.style.cursor = "url(./resource/img/topo/openhand.cur) 8 8, default";
				}
				if (this.isLinkMode && this.isLinking) {
					this.container.style.cursor = "crosshair";
					var mouseX = eventTool.getX(e.event);
					var mouseY = eventTool.getY(e.event);
					if (!this._linkLine) {
						this._linkLine = new Arrow({
							hoverable: false,
							style: {
								color: 'rgb(0,0,0)',
								strokeColor: 'rgb(26,179,148)',
								xStart: this._lineBeginPos[0],
								yStart: this._lineBeginPos[1],
								xEnd: mouseX,
								yEnd: mouseY,
								lineWidth: 3
							}
						});
						this.mainGroup.addChild(this._linkLine);
					} else {
						this.zr.modElement(this._linkLine.id, {
							style: {
								xEnd: mouseX,
								yEnd: mouseY
							}
						});
					}
				}
			},

			_zrMouseup: function(e) {
				var ctrl = this.get("ctrl");

				if (this.isDraggingCanvas) {
					this._drogAll();
					return;
				}
				if (this.isLinkMode) {
					if (this.isLinking) {
						if (this.lineEndNodeNominee) {
							this.lineEndNode = this.lineEndNodeNominee;
							this.mainGroup.removeChild(this._linkLine);
							this.addLinkLine(this.lineBeginNode, this.lineEndNode);

							ctrl.sendAction("saveLineToServer", this.toJSON());

						} else {
							if (this._linkLine) {
								this.mainGroup.removeChild(this._linkLine);
							}
							Ember.Logger.log("cancel link");
						}
						//$(this.container.children[0]).css("cursor", "");
					}
					this.isLinking = false;
					this.lineBeginNodeNominee = null;
					this.lineEndNodeNominee = null;
					this.lineBeginNode = null;
					this.lineEndNode = null;
					this._lineBeginPos = null;
					this._linkLine = null;
				}
			},

			_zrMousewheele: function(e) {
				var arigE = e.event;
				eventTool.stop(arigE);

				var delta = arigE.wheelDelta ? arigE.wheelDelta / 120 : -(arigE.detail || 0) / 3;
				var scaling = this.getScaling(),
					mouseX = eventTool.getX(arigE),
					mouseY = eventTool.getY(arigE);
				if (delta > 0) {
					this.scale(scaling + 0.1, mouseX, mouseY);
				} else if (delta < 0) {
					this.scale(scaling - 0.1, mouseX, mouseY);
				}
			},

			//开始拖动画布上所有内容
			_dragAll: function(e) {
				this.container.style.cursor = "url(./resource/img/topo/closedhand.cur) 8 8, move";
				this.isDraggingCanvas = true;
				this._mouseX = eventTool.getX(e.event);
				this._mouseY = eventTool.getY(e.event);
			},

			//结束拖动画布上所有内容
			_drogAll: function() {
				this.container.style.cursor = "url(./resource/img/topo/openhand.cur) 8 8, default";
				this.isDraggingCanvas = false;
			},

			//移动画布上所有内容
			_moveAll: function(e) {
				var zr = this.zr;
				var lastX = this._mouseX;
				var lastY = this._mouseY;
				this._mouseX = eventTool.getX(e.event);
				this._mouseY = eventTool.getY(e.event);
				var dx = this._mouseX - lastX;
				var dy = this._mouseY - lastY;

				this.container.style.cursor = "url(./resource/img/topo/closedhand.cur) 8 8, move";

				zr.painter.eachBuildinLayer(function(layer) {
					// Keep the mouse center when scaling
					layer.position[0] += dx;
					layer.position[1] += dy;
					layer.dirty = true;
				});
				zr.refresh();
			},

			addLinkLine: function(from, to) {
				var view = this;

				var sourceIpArr = [];
				var ctrl = this.get("ctrl");
				var nodePanelsMap = this.nodePanelsMap;
				var colonyArr = [];

				//判断连线是否重复
				var isRepeat = this.relationLines.any(function(line) {
					return (line.fromPanel.id == from.id && line.toPanel.id == to.id);
				});
				if (!isRepeat) {
					var newRel = {
						from: this.lineBeginNode.id,
						to: this.lineEndNode.id
					};
					this._renderLines([newRel]);
					var relations = [newRel]

					forEach(relations, function(relation) {
						if (nodePanelsMap[relation.from].data.nodeType == 2) {
							nodePanelsMap[relation.from].data.nodeIds.forEach(function(node) {
								view.data.topoNodes.forEach(function(item) {
									if (item.id == node) {
										colonyArr.push(item.ip);
									}
								});
							});
							sourceIpArr.push({
								"from": colonyArr,
								"id": nodePanelsMap[relation.to].data.id
							});
						} else {
							sourceIpArr.push({
								"from": nodePanelsMap[relation.from].data.ip,
								"id": nodePanelsMap[relation.to].data.id
							});
						}

					});
					ctrl.sendAction("addLines", sourceIpArr);

					this.data.relations.push(newRel);
				} else {
					Ember.Logger.log("重复连线");
				}
			},

			removeLinkLine: function(data) {
				var line = this.relationLines.find(function(line) {
					return (line.fromPanel.id == data.from && line.toPanel.id == data.to);
				});

				this.data.relations.removeObject(line.data);

				this.relationLines.removeObject(line);
				line.destroy();
			},

			addNodeToCluster: function(node, clusterNode) {
				var me = this,
					nodePanelsMap = this.nodePanelsMap,
					nodePanel = nodePanelsMap[node.id],
					clusterNodePanel = nodePanelsMap[clusterNode.id];

				this.zr.animate(nodePanel.group, null, false)
					.when(300, {
						position: [clusterNodePanel.x, clusterNodePanel.y]
					})
					.done(function() {
						me.delNodes([node], true);
					})
					.start();
			},

			removeNodeFromCluster: function(node) {
				var me = this,
					nodePanelsMap = this.clusterNodePanelsMap,
					nodePanel = nodePanelsMap[node.id];

				this.zr.animate(nodePanel.group, null, false)
					.when(300, {
						position: [node.x, (this.mainGroup.position[1] + 5)]
					})
					.done(function() {
						me.clusterNodePanels.removeObject(nodePanel);

						delete nodePanelsMap[node.id];

						nodePanel.destroy();

						me._renderNodes([node]);
					})
					.start();

				return nodePanelsMap[0]
			},

			refreshLines: function(relations) {
				var me = this;
				var lines = this.relationLines;
				var relations = this.data.relations || [];

				lines.forEach(function(line) {
					line.destroy();
				});
				this.relationLines = Ember.A();
				this._renderLines(relations);
				this.zr.refreshNextFrame();
			},

			dataChange: Ember.observer("data", function() {
				this.nodePanels.forEach(function(nodePanel) {
					nodePanel.destroy();
				});
				this.clusterNodePanels.forEach(function(nodePanel) {
					nodePanel.destroy();
				});
				this.relationLines.forEach(function(line) {
					line.destroy();
				});
				this.nodePanels = Ember.A();
				this.nodePanelsMap = {};
				this.clusterNodePanels = Ember.A();
				this.clusterNodePanelsMap = {};
				this.relationLines = Ember.A();

				this.mainGroup.clearChildren();
				if (this.expandNode) {
					this.foldCluster(false);
				}

				this.zr.painter.eachBuildinLayer(function(layer) {
					// Keep the mouse center when scaling
					layer.position[0] = 0;
					layer.position[1] = 0;
					layer.dirty = true;
				});

				if (this.get("data")) {
					//渲染出节点面板
					this._renderNodes(this.data.topoNodes || []);
					//渲染节点面板间连线
					this._renderLines(this.data.relations || []);
				}
			}),

			timePointChange: Ember.observer("timePoint", function() {
				var tp = this.get("timePoint");
				forEach([].concat(this.nodePanels, this.clusterNodePanels), function(nodePanel) {
					nodePanel.set("timePoint", tp);
				});
			}),

			/**
				缩放拓扑图, 代码基于zrender Handler.js中 mousewheel改造
				@param {number} scaling 缩放比例，>1放大，<1缩小
				@param {number} [x=0] x 默认为0，缩放中心横坐标，单位px
				@param {number} [y=0] y 默认为0，缩放中心纵坐标，单位px
			*/
			scale: function(scaling, x, y) {
				var zr = this.zr;
				zr.painter.eachBuildinLayer(function(layer) {
					layer.maxZoom = 5;
					layer.minZoom = 0.5;

					var pos = layer.position;

					layer.__zoom = layer.__zoom || 1;
					var newZoom = scaling;
					newZoom = Math.max(
						Math.min(layer.maxZoom, newZoom),
						layer.minZoom
					);
					scaling = newZoom;
					var scale = newZoom / layer.__zoom;
					layer.__zoom = newZoom;
					// Keep the mouse center when scaling
					pos[0] -= (x - pos[0]) * (scale - 1);
					pos[1] -= (y - pos[1]) * (scale - 1);
					layer.scale[0] = newZoom;
					layer.scale[1] = newZoom;
					layer.dirty = true;
				});
				zr.refresh();

				this.onScaled && this.onScaled(scaling, this);
				this.trigger("caled", scaling, this);
			},

			getScaling: function() {
				return this.zr.painter._layers["0"].scale[0];
			},

			getLayerPos: function() {
				return this.zr.painter._layers["0"].position;
			},

			/**
				调整大小
			*/
			resize: function() {
				var dom = this.container;
				this.width = $(dom).width();
				this.height = $(dom).height();

				this.zr.resize();
			},

			/**
				设置节点面板的显示模式
			*/
			setDisplayMode: function(size) {
				this.nodePanels.forEach(function(nodePanel) {
					nodePanel.set("displayMode", size);
				});
				this.refreshLines();
			},

			/**
				添加节点和关系
			*/
			addNodes: function(nodes, relations) {
				var auditedData = this._addDataAudit(nodes, relations);
				this._renderNodes(nodes);
				this.refreshLines(relations);
				return auditedData;
			},

			/**
				删除节点
			*/
			delNodes: function(nodes, keepData) {
				var me = this;
				var nodePanels = this.nodePanels,
					nodePanelsMap = this.nodePanelsMap,
					allNodes = this.data.topoNodes,
					allRels = this.data.relations,
					lines = this.relationLines,
					nodesIndex = [],
					relsIndex = [],
					sendLines = [],
					sendNodes = [],
					ctrl = this.get("ctrl");

				forEach(lines, function(line, i) {
					sendLines.push(line)
				});
				forEach(allNodes, function(node, i) {
					sendNodes.push(node)
				});

				//确定删除的节点在整个拓扑图的节点的索引
				//以及其关系在整个拓扑图的关系中的索引

				forEach(nodes, function(node) {
					var nodeId = node.id;

					forEach(nodePanels, function(nodePanel, i) {
						if (nodePanel.data.id == nodeId) {
							nodesIndex.unshift(i);

						}
					});

					forEach(lines, function(line, i) {
						if (line.fromPanel.data.id == nodeId || line.toPanel.data.id == nodeId) {
							relsIndex.unshift(i);
						}
					});
				});


				//根据待删除节点索引来删除节点
				forEach(nodesIndex, function(i) {
					var panel = nodePanels[i];
					delete nodePanelsMap[panel.data.id];
					panel.destroy();

					if (!keepData) {
						allNodes.splice(i, 1);
					}
					nodePanels.splice(i, 1);
				});

				//根据待删除关系索引来删除关系
				forEach(relsIndex, function(i) {
					var line = lines[i];
					line.destroy();

					allRels.splice(i, 1);
					lines.splice(i, 1);
				});

				ctrl.sendAction("delNodesTodelIp", sendLines, sendNodes);
				this.zr.refreshNextFrame();
			},

			//审查待添加的节点和关系, 过滤掉重复、无效的节点和关系
			_addDataAudit: function(nodes, relations) {
				var allNodes = this.data.topoNodes || [],
					allRels = this.data.relations || [],
					nodesMap = {},
					relsMap = {},
					auditedNodes = [],
					auditedRels = [];

				forEach(allNodes, function(node) {
					nodesMap[node.id] = true;
				});

				forEach(allRels, function(rel) {
					relsMap[rel.from + rel.to] = true;
				});

				forEach(nodes, function(node) {
					if (!nodesMap[node.id]) {
						allNodes.push(node);
						auditedNodes.push(node);
						nodesMap[node.id] = true;
					}
				});

				forEach(relations, function(rel) {
					if (nodesMap[rel.from] && nodesMap[rel.to] && !relsMap[rel.from + rel.to]) {
						allRels.push(rel);
						auditedRels.push(rel);
					}
				});

				return {
					nodes: auditedNodes,
					relations: auditedRels
				}
			},

			/**
				返回拓扑图的JSON对象
			*/
			toJSON: function() {
				var layerPos = this.getLayerPos();
				var nodes = this.nodePanels.map(function(nodePanel) {
					var nodeData = nodePanel.data;

					var data = {
						id: nodeData.id,
						nodeType: nodeData.nodeType,
						ip: nodeData.ip,
						picUrl: nodeData.picUrl,
						port: nodeData.port,
						protocol: nodeData.protocol,
						name: nodeData.name,
						x: layerPos[0] + nodePanel.x,
						y: layerPos[1] + nodePanel.y,
						size: nodePanel.displayMode
					};
					if (nodeData.nodeType == 2) {
						data.nodeIds = zrUtil.clone(nodeData.nodeIds);
					}
					return data;
				});
				var relations = this.relationLines.map(function(line) {
					return {
						"from": line.fromPanel.data.id,
						"to": line.toPanel.data.id
					}
				});
				return {
					topoNodes: nodes,
					relations: relations
				};
			},

			/**
				展开集群面板, 显示集群下的节点
			*/
			expandCluster: function(nodeData) {
				var me = this;
				if (nodeData.nodeType != 2) {
					return;
				}

				if (this.expandNode) {
					this.foldCluster(false);
				}

				this.expandNode = this.nodePanelsMap[nodeData.id];

				//找到集群节点包含的节点数据
				var allNodes = Ember.A(this.data.topoNodes);
				var allNodesMap = {};
				allNodes.forEach(function(node) {
					allNodesMap[node.id] = node;
				});

				var nodes = map(nodeData.nodeIds || [], function(nodeId) {
					return allNodesMap[nodeId];
				});
				//nodes.unshift(zrUtil.clone(nodeData));

				var clusterGroup = new Group({});
				this.group.addChild(clusterGroup);
				this.clusterGroup = clusterGroup;

				this.mainGroup.ignore = true;

				//根据上述节点数据渲染出一些临时的节点面板
				me._renderClusterHeader();
				me._renderClusterNodes(nodes);
				this._playExpandAnimation();
			},

			/**
				收起集群面板
			*/
			foldCluster: function(animate) {
				var me = this,
					zr = this.zr;

				var _foldCluster = function() {
					me.expandNode = null;

					me._clearLastClusterNodes();

					if (me.clusterGroup) {
						me.group.removeChild(me.clusterGroup);
						me.clusterGroup = null;
						me.btnBack = null;
					}

					me.mainGroup.ignore = false;
					zr.render();
				};

				var defer = me._playFoldAnimation();

				if (animate && defer && defer.done) {
					defer.done(_foldCluster);
				} else {
					_foldCluster();
				}
			},

			_playExpandAnimation: function() {
				var me = this,
					zr = this.zr,
					layerPos = this.getLayerPos();

				zr.animate(this.btnBack, null, false)
					.when(200, {
						position: [10 - layerPos[0], 50 - layerPos[1]]
					})
					.start();

				me.clusterNodePanels.forEach(function(nodePanel, i) {
					nodePanel.position(i * 245 + 80 - layerPos[0], 50 - layerPos[1]);
				});
			},

			_playFoldAnimation: function() {
				var me = this,
					zr = this.zr,
					layerPos = this.getLayerPos(),
					baseX = me.expandNode.x,
					baseY = me.expandNode.y,
					_flodCluster;

				me.clusterNodePanels.forEach(function(nodePanel, i) {
					nodePanel.position(i * 5 + baseX, baseY);
				});

				_flodCluster = zr.animate(this.btnBack, null, false)
					.when(200, {
						position: [-50 - layerPos[0], 50 - layerPos[1]]
					})
					.start();

				return _flodCluster;
			},

			_clearLastClusterNodes: function() {
				this.clusterNodePanels.forEach(function(nodePanel) {
					nodePanel.destroy();
				});
				this.clusterNodePanels = Ember.A();
				this.clusterNodePanelsMap = {};
				this.clusterGroup && this.clusterGroup.clearChildren();
			},

			_renderClusterHeader: function() {
				var me = this;
				var layerPos = this.getLayerPos();
				var btnBack = new ImageShape({
					hoverable: false,
					clickable: true,
					position: [-50 - layerPos[0], 50 - layerPos[1]],
					style: {
						x: 0,
						y: 0,
						width: 50,
						height: 50,
						image: "resource/img/topo/icon-back.png"
					},
					onclick: function() {
						me.foldCluster(true);
					}
				});
				this.clusterGroup.addChild(btnBack);
				this.btnBack = btnBack;
			},

			_renderClusterNodes: function(nodes) {
				var me = this;
				var nodePanels = this.clusterNodePanels;
				var nodePanelsMap = this.clusterNodePanelsMap;
				var baseX = me.expandNode.x,
					baseY = me.expandNode.y;

				for (var i = 0, l = nodes.length; i < l; i++) {
					var node = nodes[i];
					node.x = i * 5 + baseX;
					node.y = baseY;
					node.size = "large";
					var panel = me._renderNode(node, "clusterGroup");
					if (i == 0) {
						panel.isExpanded = true;
					}
					panel.render();
					panel.set("draggable", false);
					nodePanels.push(panel);
					nodePanelsMap[node.id] = panel;
				}
			},

			/**
				设置指定节点的显示模式
			*/
			changeDisplayModeOf: function(node) {
				var sizes = Ember.A(["small", "full"]);
				var nodePanel = this.nodePanelsMap[node.id];
				var curSizeIndex = sizes.indexOf(node.size);

				if (!nodePanel) {
					return;
				}

				curSizeIndex++;
				if (curSizeIndex > 1) {
					curSizeIndex = 0;
				}

				nodePanel.set("displayMode", sizes[curSizeIndex]);
				this.refreshLines();
			},

			setLinkNodeMode: function(flag) {
				this.isLinkMode = flag;
				var nodePanels = this.nodePanels;
				forEach(nodePanels, function(nodePanel) {
					nodePanel.set("draggable", !flag);
				});
			},

			updateHeader: function(node) {
				var nodePanel = this.nodePanelsMap[node.id];
				if (nodePanel) {
					nodePanel.data = node;
				}
				if (!nodePanel) {
					nodePanel = this.clusterNodePanelsMap[node.id];
				}
				nodePanel.updateHeader();
			},

			updatePerformances: function(data) {
				forEach([].concat(this.nodePanels, this.clusterNodePanels), function(nodePanel) {
					if (data[nodePanel.id]) {
						nodePanel.updatePerformances(data[nodePanel.id]);
					}
				});
			},

			/**
				销毁拓扑图
			*/
			destroy: function() {
				this._super();

				this.container = null;
				this.zr.dispose();
				this.zr = null;
			}
		});

		return BusinessTopo;
	}
);